#include <xpam/system/process.h>
#include <xpam/exception.h>

namespace xpam
{
    namespace system
    {
        process::process()
        {
            _pid = 0;
        }

        void process::create(const std::string & procName, const std::string & args)
        {
            STARTUPINFOA si;
            memset(&si, 0, sizeof(si));
            si.cb = sizeof(si);
            if (_stdin.is_valid_handle() ||
                _stdout.is_valid_handle() ||
                _stderr.is_valid_handle())
            {
                si.hStdInput = _stdin.internal_handle();
                si.hStdOutput = _stdout.internal_handle();
                si.hStdError = _stderr.internal_handle();
                si.dwFlags |= STARTF_USESTDHANDLES;
            }
            PROCESS_INFORMATION pi;
            SECURITY_ATTRIBUTES p_sa, t_sa;
            memset(&p_sa, 0, sizeof(SECURITY_ATTRIBUTES));
            p_sa.nLength = sizeof(SECURITY_ATTRIBUTES);
            memset(&t_sa, 0, sizeof(SECURITY_ATTRIBUTES));
            t_sa.nLength = sizeof(SECURITY_ATTRIBUTES);

            if (CreateProcessA(
                procName.empty() ? 0 : procName.c_str(), // No module name (use command line)
                (char*)args.c_str(), // Command line
                &p_sa, // Process handle not inheritable
                &t_sa, // Thread handle not inheritable
                true, // bInheritHandles
                CREATE_NEW_CONSOLE, // dwCreationFlags
                0, // lpEnvironment
                _currentDir.empty() ? 0 :_currentDir.c_str(), // lpCurrentDirectory
                &si, // lpStartupInfo
                &pi // lpProcessInformation
                ))
            {
                _handle = pi.hProcess;
                CloseHandle(pi.hThread);
            }
            else
                throw xpam::exception() << "process::create(), error = " << GetLastError();
        }

        void process::terminate()
        {
            TerminateProcess(internal_handle(), 0);
        }

        void process::stdin_handle(const handle & h)
        {
            _stdin.internal_handle(h.internal_handle());
        }
        void process::stdout_handle(const handle & h)
        {
            _stdout.internal_handle(h.internal_handle());
        }
        void process::stderr_handle(const handle & h)
        {
            _stderr.internal_handle(h.internal_handle());
        }
    }
}